library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity processor is 
port(
	clk, reset: in std_logic;
	instruction_in: in std_logic_vector(15 downto 0);
	get_next_instruction: out std_logic;
	datapath_out: out std_logic_vector(7 downto 0));
end processor;
  
architecture behaviourial of processor is
begin
signal instruction: std_logic_vector (15 downto 0);
signal load_ir: std_logic;
signal state: std_logic)vector (2 downto 0);
signal mux1out : std_logic_vector(7 downto 0);
signal regfileout : std_logic_vector(7 downto 0);
signal regaout : std_logic_vector(7 downto 0);
signal regbout : std_logic_vector(7 downto 0);
signal mux2out : std_logic_vector(7 downto 0);
signal aluout : std_logic_vector(7 downto 0);
signal regcout : std_logic_vector(7 downto 0);
type REGARRAY is array (7 downto 0) of std_logic_vector(7 downto 0);
signal reg : REGARRAY;  -- the storage for the register file

-- INSTRUCTION REGISTER: PURELY SEQUENTIAL
process (clk)
  begin
    if (clk = '1' and clk'event) then
      if (load_ir = '1') then
        instruction <= instruction_in;
      end if;
    end if;
end process;

-- STATE MACHINE: SEQUENTIAL WITH ASYNCHRONOUS RESET
process (clk,reset)
  variable present_state: std_logic_vector( 2 downto 0);
  variable next_state: std_logic_vector (2 downto 0);
  begin
    if (reset = '0') then
      next_state := "000";
      present_state := next_state;
      get_next_instruction <= '1';
    elsif (clk = '1' and clk'event) then  
      case (present_state) is
        when "000" => next_state := "001";                                   
        when "001" => next_state := "010";         
        when "010" => if (instruction(15) = '0') then
                        next_state := "000";
                      else
                        next_state := "011";
                      end if;
        when "011" => next_state := "100";
        when "100" => if (instruction(14) = '0') then
                        next_state := "101";
                      else
                        next_state := "000";
        when others =>  next_state := "000"; -- when "101"
      end case;
      present_state := next_state;
      case (present_state) is
        when "000" => get_next_instruction <= '1';
        when "001" => load_ir <= '1';
        when "010" => state <= "001";-- 1 clock cycle
        when "011" => state <= "010"; -- 2 clock cycle
        when "100" => state <= "011"; -- 3 clock cycles
        when others => state <= "100"; -- 4 clock cycles -- when "101"
      end case;
      
          
    end if;
end process;

-- DECODE LOGIC BLOCK: PURELY COMBINATIONAL
process (instruction,state)
  begin
  case(instruction(15 downto 11)) is
    -- ADD
    when "10110" => 
    -- MOVE
    when "11001" =>
    -- SUB
    when "10011" =>
      
    -- LOAD
    when "01010" => if (state = "001") then
      
                    end if;
      
    -- MUL
    when "10101" =>
    -- AND
    when "10100" =>
    -- INC
    when "11010" => -- OR WHEN OTHERS???
  end case;

end process;

-- DATAPATH ( FROM LAB 3)

-- Mux1 process: Type 1
process(regcout,datapath_in,mux1sel)
  begin
  case (mux1sel) is
    when '0' => mux1out <= regcout;
    when others => mux1out <= datapath_in;
  end case;
end process;

-- Register file: Type 1 & Type 2
-- Type 1: READ
process(reg,readnum)
  begin
    regfileout <= reg (conv_integer (readnum));
end process;

-- Type 2: WRITE
process(clk)
  begin
    if (clk = '1' and clk'event) then
      if (write = '1') then
        reg (conv_integer (writenum)) <= mux1out;        
      end if;   
    end if; 
end process;

-- register A
process(clk)
	begin
		if (clk = '1' and clk'event) then
			if (loada = '1') then
			regaout <= regfileout;
			end if;
		end if;
	end process;
	
-- register B
process(clk)
	begin
		if (clk = '1' and clk'event) then
			if (loadb = '1') then
			regbout <= regfileout;
			end if;
		end if;
	end process;
	
-- register C
process(clk)
	begin
		if (clk = '1' and clk'event) then
			if (loadc = '1') then
			regcout <= aluout;
			end if;
		end if;
	end process;
	
-- Datapath_out is whatever sits on regcout
datapath_out <= regcout;
	
--mux2
process(mux2sel,regbout)
	begin
		case (mux2sel) is
			when '0' => mux2out <= regbout;
			when others => mux2out <= "00000001";
		end case;
end process;
	
-- The Fun Part - ALU
process(funct,regaout,mux2out)
	variable multinum : std_logic_vector(15 downto 0);
	begin
		case (funct) is
			when "00" => aluout <= regaout AND mux2out;
			when "01" => multinum := (regaout * mux2out);
			             aluout <= multinum(7 downto 0);
			when "10" => aluout <= regaout + mux2out;
			when others => aluout <= regaout - mux2out;
		end case;
	end process;







end behaviourial;

     
